﻿package com.towker.core.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

/**
 * 文件对象操作类
 * @author skey
 */
public class FileUtil
{
	
	/**
	 * 将InputStream转换为字符串
	 * @param input 输入流
	 * @param charset 解码字符集
	 * @return
	 * @throws IOException
	 */
	public static String inputStream2String(InputStream input,String charset) throws IOException
	{
	  BufferedReader in = new BufferedReader(new InputStreamReader(input,charset));
	   StringBuffer buffer = new StringBuffer();
	   String line = "";
	   while ((line = in.readLine()) != null){
	     buffer.append(line +"\n");
	   }
	   return buffer.toString();

	}
	

	
	/**
	 * 输入流写入文件
	 * @param ins
	 * @param file
	 * @throws IOException
	 */
	public static void inputstreamtofile(InputStream ins,File file) throws IOException{
		OutputStream os = new FileOutputStream(file);
		int bytesRead = 0;
		byte[] buffer = new byte[8192];
		while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
		os.write(buffer, 0, bytesRead);
		}
		os.close();
		ins.close();
	}
	
	/**
	 * 将字符串转换指定字符集编码的流
	 * @param str 字符串
	 * @param charset 字符集 utf-8,gbk
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static InputStream string2InputStream(String str,String charset) throws UnsupportedEncodingException{
		   ByteArrayInputStream stream = new ByteArrayInputStream(str.getBytes(charset));
		   return stream;
	}

	 
	
	/**
	 * byte[] 转化为 InputStream
	 * @param b
	 * @return
	 */
	public static InputStream ByteToInputStream(byte[] b)
	{
		ByteArrayInputStream stream = new ByteArrayInputStream(b);
		return stream;
	}
 

	/**
	 * 将一个文件读成byte(但需要注意文件太大时，内存是否足够)
	 * @param file
	 * @return
	 */
	public static byte[] FileToByte(File file)
	{
		try
		{
			if (file == null){
				return null;
			}
			FileInputStream fin = new FileInputStream(file);
			ByteArrayOutputStream bout = new ByteArrayOutputStream(4096);
			byte[] buffer = new byte[4096];
			int bytes_read;
			while ((bytes_read = fin.read(buffer)) != -1)// Read until EOF
			{
				bout.write(buffer, 0, bytes_read);
			}
			if (fin != null){
				fin.close();
			}
			if (bout != null)
			{
				bout.close();
			}
			return bout.toByteArray();
		}
		catch(Exception ex)
		{
			return null;
		}
	}

	/**
	 * 根据文件夹路径创建文件夹
	 * @param filePath
	 */
	public static void createFolder(File file)
	{
		if (!file.exists())
		{
			file.mkdirs();
		}
	}

	/**
	 * 根据文件路径或文件夹路径创建文件夹
	 * @param filePath
	 */
	public static void createFolder(String filePath)
	{
		File f = new File(filePath);
		createFolder(f);
	}

	/**
	 * 根据文件路径或文件夹路径创建所属目录(父)路径
	 * @param filePath
	 */
	public static void createParentFolder(String filePath)
	{
		File file = new File(filePath);
		createParentFolder(file);
	}

	/**
	 * 根据文件路径或文件夹路径创建所属目录(父)路径
	 * @param filePath
	 */
	public static void createParentFolder(File file)
	{
		createFolder(file.getParent());
	}

	/**
	 * 读取文件(只支持文本文件)
	 * @param file 文件
	 * @return
	 */
	public static String readFile(File file,String charset)
	{
		try
		{
			if(!file.exists() || file.isDirectory()) return "";
			String s = inputStream2String(new FileInputStream(file),charset);
			if(s == null) return "";
			return s;
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return "";
		}
	}

	/**
	 * 读取文件(只支持文本文件)
	 * @param fileName 文件名称
	 * @return
	 */
	public static String readFile(String fileName,String charset)
	{
		if(fileName == null) return "";
		File file = new File(fileName);
		return readFile(file,charset);
	}

	/**
	 * 将指定文件流写入指定的file对象
	 * @param file
	 * @param fin
	 * @param override 是否覆盖
	 * @return 成功返回true,失败返回false
	 */
	public static boolean writeFile(File file, InputStream fin, boolean override)
	{
		try
		{
			if(!override && file.exists()) return false;
			if(file.exists() && file.isDirectory()) return false;
			// 将该数据流写入到指定文件中
			FileOutputStream fout = new FileOutputStream(file);
			byte[] buffer = new byte[4096];// To hold file contents
			int bytes_read;
			while ((bytes_read = fin.read(buffer)) != -1)// Read until EOF
			{
				fout.write(buffer, 0, bytes_read);
			}
			if (fin != null)
			{
				fin.close();
			}
			if (fout != null)
			{
				fout.close();
			}
			return true;
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
		return false;
	}

	/**
	 * 写入文件
	 * @param file 文件对象
	 * @param content 文件内容
	 * @param override 是否覆盖
	 * @return 成功返回true,失败返回false
	 * @throws UnsupportedEncodingException 
	 */
	public static boolean writeFile(File file, String content, String charset, boolean override) throws UnsupportedEncodingException
	{
		if (content == null) content = "";
		return writeFile(file, string2InputStream(content,charset), override);
	}

	/**
	 * 写入文件
	 * @param fileName 文件名称(全路径)
	 * @param content 文件内容
	 * @param override 是否覆盖
	 * @return 成功返回true,失败返回false
	 */
	public static boolean writeFile(String fileName, String content,String charset,  boolean override)
	{
		try
		{
			if (fileName == null || fileName.trim().length() == 0) return false;
			File file = new File(fileName);
			return writeFile(file, content,charset, override);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 写入文件
	 * @param file 文件对象
	 * @param content 文件内容
	 * @return 成功返回true,失败返回false
	 * @throws UnsupportedEncodingException 
	 */
	public static boolean writeFile(File file, String content,String charset) throws UnsupportedEncodingException
	{
		return writeFile(file, content,charset, true);
	}

	/**
	 * 写入文件
	 * @param fileName 文件名称(全路径)
	 * @param content 文件内容
	 * @param override 是否覆盖
	 * @return 成功返回true,失败返回false
	 */
	public static boolean writeFile(String fileName, String content,String charset)
	{
		return writeFile(fileName, content,charset, true);
	}

	/**
	 * @param from 源文件或文件夹对象
	 * @param to 目标文件或文件夹对象
	 */
	public static void copy(File from, File to)
	{
		copy(from, to, true, true);
	}

	/**
	 * @param from 源文件或文件夹路径
	 * @param to 目标文件或文件夹路径
	 */
	public static void copy(String from, String to)
	{
		copy(from, to, true, true);
	}

	/**
	 * @param from 源文件或文件夹路径
	 * @param to 目标文件或文件夹路径
	 * @param override 复制过程中遇到已存在的文件夹或文件是否覆盖改写，默认为true:覆盖
	 * @param copySubdir 复制文件夹时，是否复制子文件夹，默认为true
	 */
	public static void copy(String from, String to, boolean override, boolean copySubdir)
	{
		File fromFile = new File(from);
		File toFile = new File(to);
		copy(fromFile, toFile, override, copySubdir);
	}

	/**
	 * from复制到to
	 * @param from 源文件或文件夹对象
	 * @param to 目标文件或文件夹对象
	 * @param override 复制过程中遇到已存在的文件夹或文件是否覆盖改写，默认为true:覆盖
	 * @param copySubdir 复制文件夹时，是否复制子文件夹，默认为true
	 * @return
	 */
	public static void copy(File from, File to, boolean override, boolean copySubdir)
	{
		try
		{
			if (from == null || to == null)
				return;
			if (!from.exists())
				return;// 源文件或文件夹不存在
			if (from.isDirectory())
			{
				if (to.exists())// 当目标已存在
				{
					if (to.isFile())// 文件夹不能复制到文件中
					{
						return;
					}
					if (!override)
						return;// 当目标已存在，且不能覆盖时
				}
				if (!to.exists())
					to.mkdirs();
				String[] fileList = from.list();
				if (fileList == null)
					return;
				for (int i = 0; i < fileList.length; i++)
				{
					File f = new File(from.getAbsoluteFile() + "/" + fileList[i]);
					if (f.isDirectory() && !copySubdir)
						continue;// 不复制子目录
					File t = new File(to.getAbsoluteFile() + "/" + fileList[i]);
					copy(f, t, override, copySubdir);
				}
			}
			else if (from.isFile())
			{
				copyFile(from, to, override);
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * 复制文件from复制到to
	 * @param from 源文件或文件夹对象
	 * @param to 目标文件或文件夹对象
	 * @param override
	 * @return 返回复制结果
	 */
	public static boolean copyFile(File from, File to, boolean override)
	{
		boolean fail = false;
		try
		{
			if (from.exists() && from.isFile() && !(to.exists() && to.isDirectory()))
			{
				if (!override && to.exists()) return fail;// 当目标已存在，且不能覆盖时
				if (!to.exists())
				{
					String filePath = to.getParent();
					File f = new File(filePath);
					f.mkdirs();
				}
				return writeFile(to, (new FileInputStream(from)), override);
			}
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return fail;
	}

	/**
	 * 删除整个文件夹
	 * @param dir
	 * @return
	 */
	public static boolean deleteDir(String dirPath)
	{
		File dir = new File(dirPath);
		return delete(dir, true, true, false);
	}

	/**
	 * 删除整个文件夹
	 * @param dir
	 * @return
	 */
	public static boolean deleteDir(File dir)
	{
		return delete(dir, true, true, false);
	}

	/**
	 * 删除整个文件夹下的所有文件和子文件夹,该文件夹不删除
	 * @param dir
	 * @return
	 */
	public static boolean clearDir(String dirPath)
	{
		File dir = new File(dirPath);
		return delete(dir, false, true, false);
	}

	/**
	 * 删除整个文件夹下的所有文件和子文件夹,该文件夹不删除
	 * @param dir
	 * @return
	 */
	public static boolean clearDir(File dir)
	{
		return delete(dir, false, true, false);
	}

	/**
	 * 只删除整个文件夹下的所有文件(包括子目录),目录结构不删除
	 * @param dir
	 * @return
	 */
	public static boolean deleteAllFiles(String dirPath)
	{
		File dir = new File(dirPath);
		return delete(dir, false, true, true);
	}

	/**
	 * 只删除整个文件夹下的所有子文件夹(包括子目录), 目录结构不删除
	 * @param dir
	 * @return
	 */
	public static boolean deleteAllFiles(File dir)
	{
		return delete(dir, false, true, true);
	}

	/**
	 * 删除
	 * @param dir 删除的文件夹或文件
	 * @param isDeleteDir 是否删除此文件夹（只在删除对象为文件夹时此值有效） isDeleteDir有效且值为false时以下参数有效
	 * @param isDeleteSubDir 是否删除子文件夹
	 * @param isKeepStructure 是否保留子文件夹的目录结构
	 * @return
	 */
	public static boolean delete(File file, boolean isDeleteDir, boolean isDeleteSubDir, boolean isKeepStructure)
	{
		if (file.isDirectory())
		{
			String[] children = file.list();
			for (int i = 0; i < children.length; i++)
			{
				File subFile = new File(file, children[i]);
				if (isDeleteDir || subFile.isFile())
				{
					boolean success = delete(subFile, true, true, false);
					if (!success)
					{
						return false;
					}
				}
				else
				{
					if (isDeleteSubDir)// 是否删除子目录
					{
						boolean success = delete(subFile, !isKeepStructure, true, isKeepStructure);
						if (!success)
						{
							return false;
						}
					}
				}
			}
			if (isDeleteDir)
				return file.delete();
			return true;
		}
		else if(file.isFile())
			return file.delete();
		return false;
	}
	
	public static File getFile(String path)
	{
		try
		{
			File f = new File(path);
			return f;
		}
		catch(NullPointerException e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 根据目录取得文件列表
	 * @param path
	 * @return
	 */
	public static File[] getFiles(String path)
	{
		File file = new File(path);
		return file.listFiles();
	}

	/**
	 * 判断是否已存在同名文件,存在同名文件则重名为"原文件名(数字).原扩展名"
	 * @param fileName 文件名
	 * @param realPath 真实路径
	 * @return
	 */
	public static String getRefrainFileName(String fileName, String realPath)
	{
		if (fileName == null || fileName.trim().length() == 0)
			return "";
		String arrFileName[];
		arrFileName = fileName.split("[.]");// 正则表达式
		String fileExt = arrFileName[arrFileName.length - 1];// 文件扩展名
		String _fileName = fileName;// 保存新的文件名
		int countLogger = 1;// 记数器
		realPath = realPath + "/";
		File file = new File(realPath + fileName);// 读入文件对象
		while (file.exists())// 判断文件是否存在
		{
			int fileNameLength = fileName.lastIndexOf(".");
			if (fileNameLength >= 0 && fileNameLength < fileName.length())
			{
				_fileName = fileName.substring(0, fileNameLength) + "(" + countLogger + ")" + "." + fileExt;
			}
			else
			{
				_fileName = _fileName + "(" + countLogger + ")";
			}
			countLogger++;
			file = new File(realPath + _fileName);// 重新读入文件对象
		}
		return _fileName;
	}

	/**
	 * 返回指定文件夹或文件的大小,单位bit
	 * @param path
	 * @return
	 */
	public static long getDirSize(String path)
	{
		long rtnSize = 0;
		File file = new File(path);
		if (!file.exists())
		{
			return rtnSize;
		}
		if (!file.isDirectory())
		{
			return file.length();
		}
		String[] tempList = file.list();
		File temp = null;
		for (int i = 0; i < tempList.length; i++)
		{
			if (path.endsWith(File.separator))
			{
				temp = new File(path + tempList[i]);
			}
			else
			{
				temp = new File(path + File.separator + tempList[i]);
			}
			if (temp.isFile())
			{
				rtnSize += temp.length();
			}
			if (temp.isDirectory())
			{
				double inttemp = getDirSize(path + "/" + tempList[i]);
				rtnSize += inttemp;// 先叠加子文件夹里面的文件
			}
		}
		return rtnSize;
	}

	/**
	 * 序列化对象到文件
	 * @param obj
	 * @param fileName
	 */
	public static void serializeToFile(Object obj, String fileName)
	{
		try
		{
			ObjectOutput out = new ObjectOutputStream(new FileOutputStream(fileName));
			out.writeObject(obj);
			out.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * 从文件反序列化出对象
	 * @param fileName
	 * @return
	 */
	public static Object deserializeFromFile(String fileName)
	{
		try
		{
			File file = new File(fileName);
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
			Object obj = in.readObject();
			in.close();
			return obj;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 取得文件后缀名,文件不存在则返回null,没后缀名则返回""
	 * @param file
	 * @return
	 */
	public static String getFileExt(File file)
	{
		try
		{
			if(file.isFile())
			{
				String name = file.getName();
				int len = name.lastIndexOf(".");
				if(len != -1)
					return name.substring(len + 1);
				return "";
			}
			return null;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return null;
	}
}
